package cn.org.xuanguang.kepler.hormos.rdb.jpa.mapper;

import cn.org.xuanguang.kepler.hormos.rdb.dml.operator.delete.DeleteOperatorParameter;
import cn.org.xuanguang.kepler.hormos.rdb.dml.operator.insert.InsertOperatorParameter;
import cn.org.xuanguang.kepler.hormos.rdb.dml.operator.select.SelectOperatorParameter;
import cn.org.xuanguang.kepler.hormos.rdb.dml.operator.update.UpdateOperatorParameter;
import cn.org.xuanguang.kepler.hormos.rdb.dsl.execute.Delete;
import cn.org.xuanguang.kepler.hormos.rdb.dsl.execute.Query;
import cn.org.xuanguang.kepler.hormos.rdb.dsl.execute.Update;
import cn.org.xuanguang.kepler.metadata.relational.KeplerMetaTable;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 通过jpa把entity转成 元数据
 * <p>
 * 需要注意的地方，元数据和实体类字段名不一致，需要通过@ColumnName注解指定
 * 如果涉及到curd的时候，还需要注意实体和元数据字段的映射关系
 *
 * @author xuanguang
 */
@Data
public class JpaEntityMapper<T> {
    /**
     * 表元数据
     */
    private KeplerMetaTable metaTable;
    /**
     * jap实体类 列数据处理
     * 用来记录，字段对应的数值，包括聚合函数情况
     */
    private List<JpaColumnMapper> jpaColumnMappers = new ArrayList<>();

    /**
     * 构造函数，根据实体类Class对象获取其对应的表元数据。
     *
     * @param entity 实体类的Class对象，不能为空。
     */
    private JpaEntityMapper(Class<T> entity) {
        this.metaTable = EntityMetaTableUtils.getMetaTable(entity);
    }

    /**
     * 创建一个JpaEntityMapper的实例。
     *
     * @param entityClass 要映射的实体类的Class对象，不能为空。
     * @param <T>         实体类必须是IEntity的子类。
     * @return JpaEntityMapper的实例。
     * @throws IllegalArgumentException 如果entityClass为null，抛出此异常。
     * @throws RuntimeException         如果JpaEntityMapper的实例化过程中遇到任何异常，抛出此异常。
     */
    public static <T> JpaEntityMapper of(Class<T> entityClass) {
        if (entityClass == null) {
            throw new IllegalArgumentException("entityClass cannot be null");
        }

        try {
            return new JpaEntityMapper(entityClass);
        } catch (Exception e) {
            throw new RuntimeException("Failed to create JpaEntityMapper for entity class: " + entityClass.getName(), e);
        }
    }

    /**
     * 根据提供的实体对象组装元数据和实体数据的对应关系。
     *
     * @param entity 实体对象。
     * @return JpaEntityMapper自身实例，支持链式调用。
     */
    public JpaEntityMapper dsl(T entity) {
        // 组装mate和entity的数据对应关系
        MetaTableToDslUtils.dsl(metaTable, entity, jpaColumnMappers);
        return this;
    }

    /**
     * 根据当前配置的元数据和实体字段映射关系，生成插入操作的参数。
     * @param insertOperatorParameter 入参，需要显示指明，为了方便租户，等策略的加载使用
     *
     * @return 插入操作所需的参数对象。
     */
    public InsertOperatorParameter insert(InsertOperatorParameter insertOperatorParameter) {
        insertOperatorParameter.setTableName(metaTable.getSchemaTableName());
        insertOperatorParameter.getColumns().addAll(jpaColumnMappers.stream().map(JpaColumnMapper::getColumn).collect(Collectors.toList()));
        insertOperatorParameter.getValues().addAll(jpaColumnMappers.stream().map(JpaColumnMapper::getValue).collect(Collectors.toList()));
        return insertOperatorParameter;
    }

    public DeleteOperatorParameter delete(Delete delete) {
        DeleteOperatorParameter deleteOperatorParameter = new DeleteOperatorParameter();
        deleteOperatorParameter.setTableName(metaTable.getSchemaTableName());
        deleteOperatorParameter.setTerms(delete.getParam().getTerms());
        return deleteOperatorParameter;

    }

    public UpdateOperatorParameter update(Update update) {
        UpdateOperatorParameter updateOperatorParameter = new UpdateOperatorParameter();
        updateOperatorParameter.setTableName(metaTable.getSchemaTableName());
        updateOperatorParameter.setTerms(update.getParam().getTerms());
        updateOperatorParameter.setColumns(jpaColumnMappers.stream().map(JpaColumnMapper::getColumn).collect(Collectors.toList()));
        updateOperatorParameter.setValues(jpaColumnMappers.stream().map(JpaColumnMapper::getValue).collect(Collectors.toList()));
        return updateOperatorParameter;

    }

    public SelectOperatorParameter select(Query query) {
        SelectOperatorParameter selectOperatorParameter = new SelectOperatorParameter();
        selectOperatorParameter.setTableName(metaTable.getSchemaTableName());
        selectOperatorParameter.setTerms(query.getParam().getTerms());
        selectOperatorParameter.setColumns(jpaColumnMappers.stream().map(JpaColumnMapper::getColumn).collect(Collectors.toList()));
        return selectOperatorParameter;
    }
}
